//
//  PulldownRefreshControl.swift
//  Wei91BoiOS
//
//  Created by bing on 16/3/28.
//  Copyright © 2016年 bing. All rights reserved.
//

import UIKit

/*
    封装框架
    1.尽量少的依赖其他框架
    2.不想给别人使用的属性或方法不要暴露出来
    3.高内聚，低耦合尽量少的依赖其他对象
    4.使用简单，暴露的方法名称注意

*/

// MARK: - 扩展UIScrollView,动态添加下拉刷新控件属性,方便UIScrollView使用下拉刷新

private var pullDownRefreshControlKey = "pullDownRefreshControlKey"

extension UIScrollView {
    /// 计算型属性，计算型属性只是生成getter和setter方法
    /// 使用运行时，动态关联队形，操作起来和字典
    private  var pullDownRefreshControl: PulldownRefreshControl {
        
        get {
            // 来对象身上根据key来取东西
            // object:AnyObject!:要取东西的对象
            // key: key一定哟啊记得加&
            if let refreshControl = objc_getAssociatedObject(self, &pullDownRefreshControlKey) as? PulldownRefreshControl {
                return refreshControl
            } else {
                // 在对象身上没找到需要的东西
                let refreshControl = PulldownRefreshControl()
                
                // 添加到scrollView上面
                self.addSubview(refreshControl)
                // 将refreshControl关联到self,回调用setter方法
                self.pullDownRefreshControl = refreshControl
                
                return refreshControl
            }
        }
        set {
            // 将newValue添加到self身上
            // object:AnyObject！: 要添加东西的对象
            // key:key一定要记得加&
            // value：AnyObject!: 要添加的东西
            // policy:object_
            objc_setAssociatedObject(self, &pullDownRefreshControlKey, newValue
                , objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    // MARK: - 添加3个对外公开的方法，不让外部直接访问下控件
    /// 添加开始刷新的闭包
    func addPullDownRefreshHandler(handler: () -> ()) {
        pullDownRefreshControl.pulldownRefreshHandler = handler
    }
    
    /// 开始刷新
    func startRefreshing() {
        pullDownRefreshControl.startRefreshing()
    }
    
    /// 结束刷新
    func endRefreshing() {
        pullDownRefreshControl.endRefreshing()
    }
}

private let PulldownReshControlHeight: CGFloat = 60
/// 刷新控件的3种状态
enum PulldownRefreshControlStatue: Int {
    
    case Normal        // 箭头朝下，下拉刷新
    case PullToRefresh // 箭头朝上，释放刷新
    case Refreshing    // 正在刷新
}

class PulldownRefreshControl: UIView {
    
    // MARK: - 属性
    /// 刷新控件开始刷新的回调
    var pulldownRefreshHandler: (()->())?
    
    /// 父类,定义属性的时候属性类型后面!
    /// UIScrollView!: 表示可选类型,隐式拆包,在使用的时候可以不用强制拆包,需要保证在使用的时候一定有值.如果值为nil,也是会挂掉
    /// 和?有区别.UIScrollView?,后面使用需要强制拆包
    /// UIScrollView!: 后面使用不需要强制拆包.如果值为nil,也是会挂掉
    private weak var scrollView: UIScrollView!
    
    // 记录上一次的状态
    private var oldStatus: PulldownRefreshControlStatue = .Normal
    
    /// 刷新控件的当前刷新状态，默认是Normal:箭头朝下，下拉刷新箭头朝上
    private var currentStatus: PulldownRefreshControlStatue = .Normal {
        didSet {
            // 状态改变来改变UI
            switch currentStatus {
            case .Normal:
                fhlView.layer.removeAllAnimations()
                // 箭头转下来，文字变为：下拉刷新
                messageLabel.text = "下拉刷新"
                // 移除风火轮的旋转动画
                arrowView.hidden = false
                fhlView.hidden = true
                
                UIView.animateWithDuration(QBDefaultDuration, animations: { () -> Void in
                    
                    self.arrowView.transform = CGAffineTransformIdentity
                })
                
                // 只有上次是刷新状态，在切换到Normal状态的时候，才让tabelView往上走刷新控件的高度，把控件隐藏掉
                if oldStatus == .Refreshing {
                    
                    UIView.animateWithDuration(QBDefaultDuration, animations: { () -> Void in
                        
                        self.scrollView.contentInset.top -= PulldownReshControlHeight
                        
                        },completion:nil)
                }
 
            case .PullToRefresh:
                // 箭头旋转,文字变为: 释放刷新
                messageLabel.text = "释放刷新"
                UIView.animateWithDuration(QBDefaultDuration, animations: { () -> Void in
                    self.arrowView.transform = CGAffineTransformMakeRotation(CGFloat(M_PI))
                })
                
            case .Refreshing:
                // 箭头隐藏,文字变为正在刷新
                arrowView.hidden = true
                fhlView.hidden = false
                messageLabel.text = "正在刷新....."
                
                let rotation = CABasicAnimation(keyPath: "transform.rotation")
                rotation.toValue = M_PI * 2
                rotation.duration = 0.5
                rotation.repeatCount = MAXFLOAT
                // forKey:如果传nil,动画叠加, forKey:不等于nil,重新动画
                fhlView.layer.addAnimation(rotation, forKey: "rotation")
                UIView.animateWithDuration(QBDefaultDuration, animations: { () -> Void in
                    self.scrollView.contentInset.top += PulldownReshControlHeight
                    },completion: {(_) -> Void in
                        // 刷新控件动画到导航栏下方的时候调用
                        self.pulldownRefreshHandler?()
                })
            }
            // 需要在didSet最下面来赋值之前的状态
            oldStatus = currentStatus
        }
    }
    
    // MARK: - 公开方法
    /// 开始刷新
    func startRefreshing() {
        
        currentStatus = .Refreshing
    }
    /// 结束刷新，别人加载到数据后来调用
    func endRefreshing() {
        
        currentStatus = .Normal
    }
    
    /// view即将被添加到父控件上面，调用addSubView后触发
    /// newSuper:父类
    override func willMoveToSuperview(newSuperview: UIView?) {
        // 记得调用父类
        super.willMoveToSuperview(newSuperview)
        
        // KVO,监听父类对象属性的改变tableView，contentOffset
        if let scrollView = newSuperview as? UIScrollView {
            self.scrollView = scrollView
            
            scrollView.addObserver(self, forKeyPath: "contentOffset", options: [NSKeyValueObservingOptions.New,NSKeyValueObservingOptions.Old], context: nil)
        }
    }
    /*
    keyPath:Optional("contentOffset"),change:Optional(["kind": 1])
    scrollView.contentOffset:(0.0, -64.0)
    
    keyPath:Optional("contentOffset"),change:Optional(["new": NSPoint: {0, -64}, "kind": 1])
    scrollView.contentOffset:(0.0, -64.0)
    */
    override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
        
        // QBPrint(msg: "keyPath:\(keyPath),change:\(change)")
        // QBPrint(msg: "scrollView.contentOffset:\(scrollView.contentOffset)")
        
        if self.scrollView.dragging {
            
            // 手指拖动tableView, Normal <-> PullToRefresh之间的状态切换
            //QBPrint(msg: "scrollView.contentInset.top:\(scrollView.contentInset.top)")
            if currentStatus == .PullToRefresh && scrollView.contentOffset.y > -scrollView.contentInset.top - PulldownReshControlHeight {
                
                QBPrint(msg: "切换到Normal")
                currentStatus = .Normal
                
            } else if currentStatus == .Normal && scrollView.contentOffset.y < -scrollView.contentInset.top - PulldownReshControlHeight {
                
                QBPrint(msg: "切换到PullTopRefresh")
                currentStatus = .PullToRefresh
            }
        } else if currentStatus == .PullToRefresh {
            // 手指松开
            // 当手指的时候，如果是PullToRefresh状态就切换到Refreshing,正在刷新，手指推动是没有反应
            QBPrint(msg: "切换到Refreshing")
            
            currentStatus = .Refreshing
        }
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // 移除KVO
    deinit {
        scrollView.removeObserver(self, forKeyPath: "contentOffset")
    }
    
    /// 只要代码创建控件都会走这里，如果别人没有传frame,frame就是CGRectZero
    // 不管别人传入什么样的frame都设置成自己的frame
    override init(frame: CGRect) {
        let newFrame = CGRect(x: 0, y: -PulldownReshControlHeight , width: UIScreen.width, height: PulldownReshControlHeight)
        super.init(frame: newFrame)
        
        prepareUI()
    }
    
    private func prepareUI() {
       //backgroundColor = UIColor.brownColor()
        
        // 添加子控件
        addSubview(arrowView)
        addSubview(fhlView)
        addSubview(messageLabel)
        
        // 隐藏风火轮
        fhlView.hidden = true
        
        // 添加约束,如果想给比人用,最好不要依赖太多,尽量使用系统的API
        arrowView.translatesAutoresizingMaskIntoConstraints = false
        fhlView.translatesAutoresizingMaskIntoConstraints = false
        messageLabel.translatesAutoresizingMaskIntoConstraints = false
        
        // 箭头
        addConstraint(NSLayoutConstraint(item: arrowView, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: -30))
        addConstraint(NSLayoutConstraint(item: arrowView, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0))
        
        // 风火轮
        addConstraint(NSLayoutConstraint(item: fhlView, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: arrowView, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0))
        addConstraint(NSLayoutConstraint(item: fhlView, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: arrowView, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0))
        
        // messageLabel
        addConstraint(NSLayoutConstraint(item: messageLabel, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: arrowView, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 10))
        addConstraint(NSLayoutConstraint(item: messageLabel, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: arrowView, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0))
    }
    
    // MARK: - 懒加载
    /// 箭头
    private lazy var arrowView: UIImageView = UIImageView(image: UIImage(named: "tableview_pull_refresh"))
    
    /// 风火轮
    private lazy var fhlView: UIImageView = UIImageView(image: UIImage(named: "tableview_loading"))
    
    private lazy var messageLabel: UILabel = {
        let label = UILabel()
        
        // 设置
        label.textColor = UIColor.darkGrayColor()
        label.font = UIFont.systemFontOfSize(14)
        label.text = "下拉刷新"
        
        return label
    }()
}
